//
//  PlayerController.swift
//  黑胶唱片播放界面
//
//  Created by smile on 2019/4/13.
//  Copyright © 2019 ixuea. All rights reserved.
//

import UIKit

//发布订阅框架
import SwiftEventBus

class PlayerController: BaseTitleController {
    
    /// 歌词填充多个占位数据
    private var lyricPlaceholderSize=4
    
    // MARK: -  背景
    
    /// 最外层背景图
    @IBOutlet weak var ivBackgroud: UIImageView!
    
    /// 黑胶唱片后面白圈
    @IBOutlet weak var recordBackgroundBorder: UIImageView!
    
    // MARK: -  黑胶唱片列表
    
    /// 黑胶唱片列表
    /// 还要将Layout Margin设置为0
    @IBOutlet weak var collectionView: UICollectionView!
    
    //黑胶唱片指针
    @IBOutlet weak var recordThumb: UIImageView!
    
    // MARK: -  迷你控制栏
    
    /// 喜欢按钮
    @IBOutlet weak var btLike: UIButton!
    
    /// 下载按钮
    @IBOutlet weak var btDownload: UIButton!
    
    /// 均衡器按钮
    /// 未实现
    /// 因为AVPlayer无法实现均衡器
    /// 可以用系统的另一个控件实现
    /// 但他不能直接播放在线音乐
    /// 所以这一块还是比较复杂的
    /// 如果有需要开一个小课程单独讲解
    /// 因为如果不是专门做一个商业用的音乐软件
    /// 不需要均衡器
    @IBOutlet weak var btEqualizer: UIButton!
    
    /// 评论按钮
    @IBOutlet weak var btComment: UIButton!
    
    /// 更多按钮
    @IBOutlet weak var btMusicMore: UIButton!
    
    // MARK: -  进度控制
    /// 播放位置
    @IBOutlet weak var lbStart: UILabel!
    
    /// 进度条
    @IBOutlet weak var sdProgress: UISlider!
    
    /// 结束位置
    @IBOutlet weak var lbEnd: UILabel!
   
    // MARK: -  控制按钮
    /// 循环模式
    @IBOutlet weak var btLoopModel: UIButton!
    
    /// 上一曲按钮
    @IBOutlet weak var btPrevious: UIButton!
    
    
    /// 播放按钮
    @IBOutlet weak var btPlay: UIButton!
    
    /// 下一曲按钮
    @IBOutlet weak var btNext: UIButton!
    
    /// 歌曲列表
    @IBOutlet weak var btList: UIButton!
    
    
    // MARK: -  歌词相关
    
    /// 歌词列表控件
    @IBOutlet weak var tableView: UITableView!
    
    /// 拖拽状态容器
    @IBOutlet weak var dragContainer: UIStackView!
    
    /// 当前时间
    @IBOutlet weak var lbTime: UILabel!
    
    /// 歌词容器
    @IBOutlet weak var lyricContainer: UIView!
    
    /// 当前歌词行号
    var lineNumber:Int = 0
    
    /// 滚动时
    /// 当前这行歌词
    var scrollSelectedLyricLine:LyricLine?
    
    var isDrag = false
    
    var lyric:Lyric!
    
    var dataArray:[Any] = []
    
    var isTouchSlide = false
    
    // MARK: -  下载相关
    var currentCell:SongRecordCell?
    
    var downloader:DownloadManager!
    
    var orm:ORMUtil!
    
    /// 下载管理器
    var downloadInfo:DownloadInfo?
    
    var playListManager:PlayListManager!
    var musicPlayerManager:MusicPlayerManager!

    // MARK: -  初始化方法
    
    override func initViews() {
        super.initViews()
        
        //进度条
        //设置进度颜色
        sdProgress.minimumTrackTintColor=UIColor(hex: COLOR_PRIMARY)
        
        //拖动点颜色
        sdProgress.thumbTintColor = UIColor(hex: COLOR_PRIMARY)
        
        //默认进度颜色
        //    self.sbProgress.maximumTrackTintColor=[UIColor greenColor];
        
        //还可以设置图片
        //    self.sbProgress.minimumValueImage=[UIImage imageNamed:@"LoginItemPhone"];
        
        //创建右侧按钮
        //分享
        let shareBarItem = UIBarButtonItem(image: UIImage(named: "Share"), style: .plain, target: self, action: #selector(onShareClick(sender:)))
        
        //更多
        let moreBarItem = UIBarButtonItem(image: UIImage(named: "MoreWhite"), style: .plain, target: self, action: #selector(onMoreClick(sender:)))
        
        //将BarItem设置到导航栏右侧
        //排序为：从右到左排序
        navigationItem.rightBarButtonItems=[moreBarItem,shareBarItem]
 
        //使用一个异步任务
        //就可以获取到AutoLayout计算后尺寸
        //当然还有其他方法也可以
        DispatchQueue.main.async {
            // 根据黑胶唱片指针计算得出
            // 旋转的锚点为0.181,0.120
            self.recordThumb.setViewAnchorPoint(CGPoint(x: 0.181, y: 0.120))
        }
    }
    
    override func initDatas() {
        super.initDatas()
        playListManager=PlayListManager.shared
        musicPlayerManager=MusicPlayerManager.shared()

        //初始化下载管理器
        downloader=DownloadManager.sharedInstance()
        
        //初始化ORM工具类
        //主要用来保存音乐业务数据
        orm=ORMUtil.shared()
        
        //第一次进入界面
        //要显示这首音乐的初始化数据
        showInitData()
        showDuration()
        showProgress()
        showMusicPlayStatus()
        
        showLyricData()
        
        showLoopModel()
    }
    
    override func initListeners() {
        super.initListeners()
        
        //歌词View点击
        //显示黑胶唱片
        let lyricViewGestureRecognizer=UITapGestureRecognizer(target: self, action: #selector(showRecordView))
        tableView.addGestureRecognizer(lyricViewGestureRecognizer)
        
        //CollectionView点击
        //显示歌词
        let coverViewGestureRecognizer=UITapGestureRecognizer(target: self, action: #selector(showLyricView))
        collectionView.addGestureRecognizer(coverViewGestureRecognizer)

        //歌词长按
        let onLyricLongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(onLyricLongClick(gesture:)))
        
        onLyricLongPressGestureRecognizer.minimumPressDuration = 1.0
        tableView.addGestureRecognizer(onLyricLongPressGestureRecognizer)
        
        //封面长按
        let onCoverLongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(onCoverLongClick(gesture:)))
        
        onCoverLongPressGestureRecognizer.minimumPressDuration = 1.0
        collectionView.addGestureRecognizer(onCoverLongPressGestureRecognizer)
        
        //监听要关闭播放界面事件
        SwiftEventBus.onMainThread(self, name: CLOSE_PLAY_PAGE) { result in
            self.navigationController!.popViewController(animated: true)
        }
    }
    
    /// 封面长按事件回调方法
    ///
    /// - Parameter gesture: <#gesture description#>
    @objc func onCoverLongClick(gesture:UILongPressGestureRecognizer) {
        //会调用多次
        //所以通过判断过滤掉
        if gesture.state != UIGestureRecognizer.State.began {
            return
        }
        print("PlayerController onCoverLongClick")
        
        //启动图片预览控制器
        ImagePreviewController.start(navigationController!, playListManager.getPlaySong()!.banner)
    }
    
    /// 歌词长按回调方法
    ///
    /// - Parameter gesture: <#gesture description#>
    @objc func onLyricLongClick(gesture:UILongPressGestureRecognizer) {
        //会调用多次
        //所以通过判断过滤掉
        if gesture.state != UIGestureRecognizer.State.began {
            return
        }
        
        print("PlayerController onLyricLongClick:\(gesture.state)")
        
        SelectLyricController.start(self.navigationController!, playListManager.getPlaySong()!, lyric)
    }
 
    /// 显示封面(CollectionView)
    @objc func showRecordView() {
        //将他们都显示出来
        collectionView.isHidden=false
        recordBackgroundBorder.isHidden=false
        recordThumb.isHidden=false
        
        //执行动画
        UIView.animate(withDuration: 0.5, animations: {
            //动画逻辑
            //歌词View从原来的alpha(1.0)变为0
            self.lyricContainer.alpha=0.0
            
            //其他控件(CollectionView，黑胶唱片背景，唱片指针)
            //从0变为1.0
            self.collectionView.alpha            = 1.0
            self.recordBackgroundBorder.alpha            = 1.0
            self.recordThumb.alpha            = 1.0
            
        }) { (finished) in
            //动画完成时，将歌词View隐藏
            self.lyricContainer.isHidden           = true
        }
        
    }
    
    
    /// 显示歌词View
    @objc func showLyricView() {
        //先显示出歌词容器
        lyricContainer.isHidden           = false
        
        //使用动画的方式显示
        UIView.animate(withDuration: 0.5, animations: {
            //要执行的动画
            //这里的逻辑是将透明度变为1
            //也就是完全不透明
            //就是显示
            self.lyricContainer.alpha            = 1.0

            self.collectionView.alpha            = 0.0
            self.recordBackgroundBorder.alpha            = 0.0
            self.recordThumb.alpha            = 0.0
        }) { (finished) in
            //动画执行完成后
            //将黑胶唱片等信息完全隐藏
            self.collectionView.isHidden           = true
            self.recordBackgroundBorder.isHidden           = true
            self.recordThumb.isHidden           = true
        }
        
    }
    
    // MARK: -  右侧按钮相关方法
    /// 点击右侧分享按钮
    ///
    /// - Parameter sender: <#sender description#>
    @objc func onShareClick(sender:UIButton) {
        print("PlayerController onShareClick")
    }
    
    /// 点击右侧更多按钮
    ///
    /// - Parameter sender: <#sender description#>
    @objc func onMoreClick(sender:UIButton) {
        print("PlayerController onMoreClick")
    }
    
    
    // MARK: -  生命周期
    /// 视图即将可见
    ///
    /// - Parameter animated: <#animated description#>
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        //设置导航栏样式
        //这里将导航栏背景设置为黑色
        //这样状态栏（有了导航栏，只能通过这种方式设置状态栏颜色）
        //标题就会变成白色
        navigationController!.navigationBar.barStyle=UIBarStyle.black
        
        //设置标题字体颜色
        navigationController!.navigationBar.titleTextAttributes=[.foregroundColor:UIColor.white]
        
        
        //设置返回按钮为白色
        navigationController!.navigationBar.tintColor=UIColor.white
        
        //导航栏透明
        //这里设置导航透明后，就没有上面的黑色了
        navigationController!.navigationBar.setBackgroundImage(UIImage(), for: .default)
        
        //设置播放代理
        musicPlayerManager.delegate=self
    }
    
    /// 视图已经可见了
    ///
    /// - Parameter animated: <#animated description#>
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        scrollPosition()
    }
    
    /// 视图即将消失
    ///
    /// - Parameter animated: animated description
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        //恢复状态栏颜色
        //因为其他界面可能当前界面样式不一样
        
        //标题就会变成黑色
        navigationController!.navigationBar.barStyle=UIBarStyle.default
        
        //设置标题字体颜色
        navigationController!.navigationBar.titleTextAttributes=[.foregroundColor:UIColor.black]
        
        //设置返回按钮为黑色
        navigationController!.navigationBar.tintColor=UIColor.black
        
        //导航栏透明
        //这里设置导航透明后，就没有上面的黑色了
        navigationController!.navigationBar.setBackgroundImage(nil, for: .default)
        
        //移除播放代理
        musicPlayerManager.delegate=nil
    }
    
    // MARK: - 迷你控制栏相关按钮
    /// 下载点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onDownloadClick(_ sender: UIButton) {
        print("PlayerController onDownloadClick")
        //下载单首歌曲；多首，和其他类型都是一样
        //查看下载框架，是否有下载任务
        if let downloadInfo = downloadInfo {
            //已经有下载任务
            
            //判断下载状态
            if DownloadStatus.completed==downloadInfo.status {
                ToastUtil.short("该歌曲已经下载了!")
            } else {
                //可以根据业务需求来增加功能
                //例如：在判断如果在暂停中，就继续下载
                ToastUtil.short("已经在下载列表中!")
            }
            
        } else {
            //创建下载任务
            
            createDownload()
        }

    }
    
    /// 创建下载任务
    func createDownload() {
        let song=playListManager.currentSong
        let urlString=ResourceUtil.resourceUri(song!.uri)
        
        //设置保存路径
        
        //保存路径在Documents目录下
        //这里要设置相对路径：CocoaDownloader/用户Id/歌曲uri
        //路径中添加用户Id是实现多用户
        //当然这里很明显的问题是
        //如果多用户都下载一首音乐
        //会导致一首音乐会下载多次
        let path="CocoaDownloader/\(PreferenceUtil.userId()!)/\(song!.uri!)"
        
        print("PlayerController download save path:\(path)")
        
        //创建下载任务
        downloadInfo=DownloadInfo()
        
        //设置保存路径
        downloadInfo!.path=path
        
        //设置下载网址
        downloadInfo!.uri=urlString
        
        //设置Id
        downloadInfo!.id=song!.uri
        
        //获取当前时间0秒后的时间，就是当前
        let date = NSDate(timeIntervalSinceNow: 0)
        
        //转为时间戳
        let currentTimeMillis=date.timeIntervalSince1970
        
        //设置创建时间
        //用于显示下载中
        //下载完成列表排序
        //默认按时间
        downloadInfo!.createdAt=currentTimeMillis
        
        //设置下载回调
        setDownloadCallback()
        
        //开始下载
        //将要下载的对象提交到下载器
        downloader.download(downloadInfo!)
        
        //保存业务数据
        orm.saveSong(song!, PreferenceUtil.userId()!)
        
        ToastUtil.short("下载任务添加成功!")
    }
    
    // MARK: - 控制栏相关按钮
    
    /// 播放模式按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onLoopModelClick(_ sender: UIButton) {
        print("PlayerController onLoopModelClick")
        
        playListManager.changeLoopModel()
        showLoopModel()
    }
    
    /// 上一曲按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onPreviousClick(_ sender: UIButton) {
        print("PlayerController onPreviousClick")
        
        if let song = playListManager.previous() {
            playListManager.play(song)
        }else{
            //TODO 正常情况下不能能走到这里
            //因为播放界面只有播放列表有数据时才能进入
            ToastUtil.short("没有可播放的音乐！")
        }
    }
    
    /// 播放按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onPlayClick(_ sender: UIButton) {
        print("PlayerController onPlayClick")
        
        playOrPause()
    }
    
    
    /// 下一曲按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onNextClick(_ sender: UIButton) {
        print("PlayerController onNextClick")
        
        if let song = playListManager.next() {
            playListManager.play(song)
        }else{
            ToastUtil.short("没有可播放的音乐！")
        }
    }
    
    /// 歌曲列表按钮点击
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onListClick(_ sender: UIButton) {
        print("PlayerController onListClick")
        
        //创建一个View
        let musicPlayListView=MusicPlayListView()
        
        //设置尺寸
        musicPlayListView.gk_size=CGSize(width: view.frame.size.width,height: view.frame.size.height/1.5)
        
        //点击了一首音乐回调
        musicPlayListView.onSongClick={
            data in
            self.playSong(data)
        }
        
        //删除一首音乐回调
        musicPlayListView.onDeleteSongClick = {
            index in
            //从黑胶唱片集合中删除
            self.collectionView.deleteItems(at: [IndexPath(item: index, section: 0)])
        }
        
        //显示这个View
        GKCover.translucentCover(from: self.view, content: musicPlayListView, animated: true)

    }
    
    /// 显示播放模式
    func showLoopModel() {
        let model=playListManager.getLoopModel()
        switch model {
        case .list:
            btLoopModel.setImage(UIImage(named: "MusicRepeatList"), for: .normal)
        case .random:
            btLoopModel.setImage(UIImage(named: "MusicRepeatRandom"), for: .normal)
        default:
            btLoopModel.setImage(UIImage(named: "MusicRepeatOne"), for: .normal)
        }
    }
    
    /// 设置音乐的一些初始化数据
    func showInitData() {
        //获取到当前正在播放的这首音乐
        let song=playListManager.currentSong
        
        //设置标题
        setTitle("\(song!.title!)-\(song!.singer.nickname!)")
        
        //显示背景图
        ImageUtil.show(ivBackgroud, song!.banner)
        
        //下载状态
        //根据Id查询当前音乐是否有下载任务
        downloadInfo=downloader.findDownloadInfo(song!.uri)
        
        //设置下载监听器
        if let _ = downloadInfo {
            //如果有下载任务
            //就设置下载回调
            setDownloadCallback()
        }
        
        //不管有没有下载任务
        //都要刷新当前界面
        //因为要显示是否下载
        refresh()
    }
    
    // MARK: - 下载相关
    func setDownloadCallback() {
        //使用弱引用
        //防止内存泄漏
         weak var weakSelf = self
        
        //设置下载回调
        downloadInfo!.downloadBlock = {
            downloadInfo in
            weakSelf?.refresh()
        }
    }
    
    /// 刷新界面上下载状态
    func refresh() {
        if let downloadInfo=downloadInfo {
            switch downloadInfo.status {
            case .completed:
                //下载完成
                btDownload.setImage(UIImage(named: "DownloadSelected"), for: .normal)
            default:
                //其他情况
                //都显示为未下载状态
                //当然这里也可以监听下载进度
                normalDownloadStatusUI()
            }
            
            //这里不需要知道更详细的下载状态
            //所以就没有判断，会在下载管理里面判断
            //打印下载进度
            let start=FileUtil.formatFileSize(downloadInfo.progress)
            let size=FileUtil.formatFileSize(downloadInfo.size)
            let progressString="\(start)/\(size)"
            print("PlayerController download progress:\(progressString)");
        } else {
            normalDownloadStatusUI()
        }
        
    }
    
    /// 显示未下载状态
    func normalDownloadStatusUI() {
        btDownload.setImage(UIImage(named: "Download"), for: .normal)
    }
    
    
    func playOrPause() {
        if musicPlayerManager.isPlaying() {
            playListManager.pause()
            
        } else {
            playListManager.resume()
            
        }
    }
    
    //根据位置，获取当前Cell
    func getCell(_ position:Int) -> LyricCell? {
        let indexPath=IndexPath(item: position, section: 0)
        return tableView.cellForRow(at: indexPath) as? LyricCell
    }
    
    // MARK: - 进度条相关
    @IBAction func onChangeProgress(_ sender: UISlider) {
        lbStart.text = TimeUtil.formatTime1(sender.value)
    }
    
    @IBAction func onSlideTouchDown(_ sender: UISlider) {
        isTouchSlide=true
    }
    
    
    @IBAction func onSlideTouchUp(_ sender: UISlider) {
        isTouchSlide=false
        
        if(sender.value>0){
            musicPlayerManager.seekTo(sender.value)
        }
    }
    
    /// 滚动到当前音乐位置
    func scrollPosition() {
        //停止原来Cell旋转
        stopRecordRotate()
        
        //将播放列表转为NSArray
        //因为我们要根据当前播放的音乐
        //计算出位置
        let playListOC = self.playListManager.getPlayList() as! NSArray
        let index = playListOC.index(of: self.playListManager.getPlaySong())
        
        //创建IndexPath
        let indexPath = IndexPath(item: index, section: 0)
        
        //滚动到当前位置
        //这里没有使用动画
        //大家可以自己调整
        self.collectionView.scrollToItem(at: indexPath, at: UICollectionView.ScrollPosition.left, animated: false)
        
        print("PlayerController scrollPosition:\(index)")
        
        DispatchQueue.main.async {
            //使用异步操作
            //这样才能获取滚动后的Cell
            
            //获取当前可视Cell
            self.currentCell = self.getVisibleCell()

            //尝试滚动黑胶唱片
            self.tryStartRecordRotate()
            
        }
    }
    
    // MARK: - 滚动相关
    /// 拖动开始调用
    ///
    /// - Parameter scrollView: <#scrollView description#>
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        print("PlayerController scrollViewWillBeginDragging:\(scrollView)")
        
        if scrollView==tableView {
            //歌词控件
            
            //显示歌词拖拽
            showDragView()
        } else {
            //黑胶唱片
            stopRecordRotate()
        }

    }
    
    /// 拖动结束（惯性滚动）
    ///
    /// - Parameter scrollView: <#scrollView description#>
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("scrollViewDidEndDecelerating")
        
        if scrollView==tableView {
            //歌词控件
            
            //减速完成后
            //在这里延时后继续滚动歌词
            prepareScrollLyricView()
        } else {
            //黑胶唱片
            
            //滚动结束后，获取当前Cell
            let currentCell=getVisibleCell()
            
            //处理播放状态
            //获取当前Cell，判断是否和原来的一样
            if (self.currentCell==currentCell) {
                //如果一样就不处理
                
                tryStartRecordRotate()
            } else {
                self.currentCell=currentCell
                
                //不一样，就要播放这首音乐
                playSong(self.currentCell!.data)
                
                //旋转当前黑胶唱片
                startRecordRotate()
            }
        }
        
        
    }
    
    /// 拖拽结束
    ///
    /// - Parameters:
    ///   - scrollView: <#scrollView description#>
    ///   - decelerate: <#decelerate description#>
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if scrollView==tableView {
            //歌词控件
            
            if (!decelerate) {
                //如果不需要减速
                //就延时后继续显示歌词
                prepareScrollLyricView()
                
            }
        } else {
            //黑胶唱片
            
        }
    }
    
    
    
    /// 滑动中
    ///
    /// - Parameter scrollView: <#scrollView description#>
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if isDrag {
            //只有拖拽状态才处理
            //因为系统滚动的时候也会调用该方法
            
            print("lyric view scrollViewDidScroll");
            
            //计算TableView垂直方向，居中index
            //获取滚动距离
            let offsetY  = scrollView.contentOffset.y
            
            //根据滚动距离计算出index
            //+tableView高度一半的目的是
            //计算tableView垂直居中的Cell索引
            //因为我们的拖拽线就是在中心
            var index = Int((offsetY+self.tableView.frame.size.height/2)/44)
            
            //获取歌词对象
            var lyric:Any? = nil
            if (index < 0) {
                //如果计算出的index小于0
                //就默认第一个歌词对象
                lyric = dataArray.first
            }else if (index > self.dataArray.count - 1) {
                //大于最后一个歌词对象（包含填充数据）
                //就是最后一行数据
                lyric = dataArray.last
            }else {
                //如果在列表范围内
                //就直接去对应位置的数据
                lyric = dataArray[index]
            }
            
            //设置滚动时间
            
            if lyric is String {
                //字符串，用来填充占位符
                lbTime.text=""
            }else{
                //真实歌词数据
                //保存到一个字段上
                scrollSelectedLyricLine=lyric as! LyricLine
                
                //格式化这行歌词开始时间
                let startTime=Float(scrollSelectedLyricLine!.startTime)/1000.0
                
                //显示到控件
                lbTime.text =  TimeUtil.formatTime1(startTime)
            }
        }
    }
    
    // MARK: - 黑胶唱片相关方法
    /// 尝试旋转黑胶唱片
    func tryStartRecordRotate() {
        if self.musicPlayerManager.isPlaying() {
            //如果正在播放音乐
            //就开始旋转
            self.startRecordRotate()
        } else {
            self.stopRecordRotate()
        }
    }
    
    /// 黑胶唱片停止滚动
    /// 指针回到暂停状态(-25度)
    func stopRecordRotate() {
        if let currentCell=currentCell {
            currentCell.stopCoverRotate()
            stopRecordThumbRotate()
        }
    }
    
    /// 黑胶唱片开始滚动
    /// 指针回到播放位置(默认)
    func startRecordRotate() {
        if let currentCell=currentCell {
            currentCell.startCoverRotate()
            startRecordThumbRotate()
        }
    }
    
    /// 获取当前界面上可见的Cell
    func getVisibleCell() -> SongRecordCell {
        let currentCell = collectionView.visibleCells.first as! SongRecordCell
        print("PlayerController getVisibleCell:\(currentCell.data.title)")
        return currentCell
    }
    
    /// 播放这首音乐
    ///
    /// - Parameter data: <#data description#>
    func playSong(_ data:Song) {
        playListManager.play(data)
    }
    
    // MARK: - 唱片指针相关方法
    /// 黑胶指针默认状态(播放状态)
    /// 定义成单独的方法
    /// 目的是以后这部分逻辑可能放到单独的View
    func startRecordThumbRotate() {
        UIView.animate(withDuration: 0.5) {
            self.recordThumb.transform=CGAffineTransform.identity
        }
    }
    
    /// 黑胶指针旋转-25度
    func stopRecordThumbRotate() {
        UIView.animate(withDuration: 0.5) {
            self.recordThumb.transform=CGAffineTransform(rotationAngle: -0.4363323)
        }
    }
    
    deinit {
        print("PlayerController deinit")
        
        //停止Cell转动
        stopRecordRotate()
    }

    // MARK: - 歌词相关方法
    /// 歌词滚动到指定行
    ///
    /// - Parameter position: <#position description#>
    func scrollLyricPosition(_ position:Int) {
        let indexPath=IndexPath(item: position, section: 0)
        tableView.selectRow(at: indexPath, animated: true, scrollPosition: .middle)
    }
    
    /// 显示歌词数据
    func showLyricData() {
        
        /// 获取当前播放的音乐
        let data = playListManager.currentSong!
        
        //清空歌词数组
        self.dataArray.removeAll()
        
        if let lyricString=data.lyric {
            //有歌词
            
            //解析歌词
            lyric=LyricParser.parse(data.style,lyricString)
            print("PlayerController showLyricData:\(lyric)")
            
            //将数据添加到列表
            //前面的占位数据
            addLyricFillData()
            
            //真实数据
            dataArray=dataArray+lyric.datas
            
            //后面的占位数据
            addLyricFillData()
        }
        
        self.tableView.reloadData()
    }
    
    /// 添加歌词占位数
    func addLyricFillData() {
        //计算占位数量
        //tableView.height/2/44
        //然后向上取整
        lyricPlaceholderSize=Int(ceil(Double(tableView.frame.height)/2.0/44.4))
        
        for _ in 0..<lyricPlaceholderSize {
            dataArray.append("fill")
        }
    }
    
    func showLyricProgress(_ progress:Float) {
        if (lyric==nil) {
            //如果没有歌词
            //就直接返回
            return
        }
        
        if isDrag {
            return
        }
        
        //获取当前时间对应的行
        //+4是因为
        //前面添加了4个占位cell
        let newLineNumber=LyricUtil.getLineNumber(lyric,progress)+lyricPlaceholderSize
        if (newLineNumber != self.lineNumber) {
            
            self.lineNumber=newLineNumber;
            
            //滚动到这一行
            scrollLyricPosition(lineNumber)
        }
        
        //如果是精确到字歌曲，还需要将时间分发到Cell中
        //因为要计算唱到那个字了
        if lyric.isAccurate {
            let cell = getCell(lineNumber)
            if let cell=cell{
                //有可能获取不到当前位置的Cell
                //因为上面使用了滚动动画
                //如果不使用滚动动画效果不太好
                cell.show(progress)
            }
            
        }
        
    }
    
    //显示拖拽效果
    func showDragView() {
        isDrag=true
        
        dragContainer.isHidden=false
    }
    
    /// 倒计时显示歌词View
    /// 这里有Bug
    /// 如果多次拖拽会有多个延迟
    /// 应该像跳过广告那样
    /// 取消前面的延迟
    func prepareScrollLyricView() {
        //4秒后继续滚动歌词
        DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
            self.enableScrollLyric()
        }
    }

    //启用歌词滚动
    func enableScrollLyric() {
        isDrag=false
       
        dragContainer.isHidden=true
    }
    
    /// 点击了歌词前面的播放按钮
    ///
    /// - Parameter sender: <#sender description#>
    @IBAction func onLyricPlayClick(_ sender: UIButton) {
        print("PlayerController onLyricPlayClick")
        
        if let data=scrollSelectedLyricLine  {
            //从当前歌词行开始播放
            //回调回来是毫秒，要转为秒
            let progress=Float(data.startTime)/1000.0
            
            //从该位置播放
            musicPlayerManager.seekTo(progress)
            
            //马上显示歌词滚动
            enableScrollLyric()
        }
    }
    
    // MARK: - 显示歌曲信息
    func showDuration() {
        let end=playListManager.currentSong!.duration
        
        if end > 0 {
            lbEnd.text=TimeUtil.formatTime1(end)
            sdProgress.maximumValue=Float(end)
        }
        
    }
    
    func showProgress() {
        let progress=playListManager.currentSong!.progress
        
        if progress > 0 {
            if(!isTouchSlide){
                lbStart.text = TimeUtil.formatTime1(progress)
                sdProgress.value=Float(progress)
            }
            
            //这里可以在优化
            //如果没有显示歌词界面
            //歌词不用滚动
            
            //显示歌词进度
            showLyricProgress(progress)
        }
    }
    
    
    /// 显示音乐播放按钮等状态
    func showMusicPlayStatus() {
        if musicPlayerManager.isPlaying() {
            showPauseStatus()
        } else {
            showPlayStatus()
        }
    }
    
    func showPauseStatus() {
        btPlay.setImage(UIImage(named: "MusicPause"), for: .normal)
    }
    
    func showPlayStatus() {
        btPlay.setImage(UIImage(named: "MusicPlay"), for: .normal)
    }
    
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

extension PlayerController:UITableViewDataSource,UITableViewDelegate{
    // MARK:- TableView数据源
    /// 返回有多个条目
    /// 和CollectionView差不多
    ///
    /// - Parameters:
    ///   - tableView: <#tableView description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataArray.count
    }
    
    /// 返回当前位置的Cell
    ///
    /// - Parameters:
    ///   - tableView: <#tableView description#>
    ///   - indexPath: <#indexPath description#>
    /// - Returns: <#return value description#>
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //获取Cell
        let cell=tableView.dequeueReusableCell(withIdentifier: CELL, for: indexPath) as! LyricCell
        
        //设置Tag
        //目的是Cell中显示位置
        //还有点击Cell更多按钮时知道是点击了那个Cell
        cell.tag=indexPath.row
        
        //取出数据
        let data=dataArray[indexPath.row]
        
        //绑定数据
        cell.bindData(data,lyric.isAccurate)
        
        return cell
    }
}


// MARK: - 启动界面
extension PlayerController{
    /// 启动界面
    ///
    static func start(_ navigationController:UINavigationController) {
        //创建控制器
        let controller=navigationController.storyboard?.instantiateViewController(withIdentifier: "Player") as! PlayerController
        
        //将控制器压入导航控制中
        navigationController.pushViewController(controller, animated: true)
        
    }
}

// MARK: - 播放管理器代理
extension PlayerController:MusicPlayerDelegate{
    func onProgress(data: Song, progress: Float, duration: Float) {
        print("PlayerController onProgress:\(progress),\(duration)")
        showProgress()
    }
    
    func onPaused(_ data: Song) {
        print("PlayerController onPaused:\(data.title)")
        showPlayStatus()
        stopRecordRotate()
    }
    
    func onPlaying(_ data: Song) {
        print("PlayerController onPlaying:\(data.title)")
        showPauseStatus()
        startRecordRotate()
    }
    
    func onPrepared(_ data: Song) {
        print("PlayerController onPrepared:\(data.title)")
        
        showInitData()
        
        showDuration()
        
        scrollPosition()
    }
    
    func onLyricChanged(_ data: Song) {
        print("PlayerController onLyricChanged:\(data.title)")
        showLyricData()
    }
    
    func onError(_ data: Song) {
        print("PlayerController onError:\(data.title)")
    }
    
}

// MARK: -  CollectionView数据源和代理
extension PlayerController:UICollectionViewDelegate,UICollectionViewDataSource {
    
    /// 返回有多个条目
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return playListManager.getPlayList()!.count
    }
    
    
    /// 返回当前位置的Cell
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - indexPath: <#indexPath description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let data=playListManager.getPlayList()![indexPath.row]
        
        let cell=collectionView.dequeueReusableCell(withReuseIdentifier: CELL, for: indexPath) as! SongRecordCell
        
        //绑定数据
        cell.bindData(data)
        
        //        [cell bindData:data indexPath:indexPath];
        
        return cell
    }
}

// MARK:- UICollectionViewDelegateFlowLayout代理相关方法
extension PlayerController:UICollectionViewDelegateFlowLayout{
    
    /// 返回CollectionView与他的父View的间距
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - collectionViewLayout: <#collectionViewLayout description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }
    
    
    /// 返回每个Cell的行间距
    /// 也就是每行之间的间距
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - collectionViewLayout: <#collectionViewLayout description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    
    /// 返回每个Cell的列间距
    /// 也就是每列之间的间距
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - collectionViewLayout: <#collectionViewLayout description#>
    ///   - section: <#section description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    
    /// 返回当前Cell的大小
    ///
    /// - Parameters:
    ///   - collectionView: <#collectionView description#>
    ///   - collectionViewLayout: <#collectionViewLayout description#>
    ///   - indexPath: <#indexPath description#>
    /// - Returns: <#return value description#>
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        //每一个Cell和CollectionView一样大
        return collectionView.frame.size
    }
}
